package com.ts.api.module.match.plan.internal.selection.strategy;

import com.gitee.apanlh.util.base.CollUtils;
import com.gitee.apanlh.util.base.IteratorUtils;
import com.gitee.apanlh.util.base.MapUtils;
import com.gitee.apanlh.util.date.DateUtils;
import com.gitee.apanlh.util.reflection.ClassConvertUtils;
import com.gitee.apanlh.util.valid.ValidParam;
import com.ts.api.common.redis.MatchProductPlanRedisKey;
import com.ts.api.module.match.plan.internal.distribute.model.PlanDistributeField;
import com.ts.api.module.match.plan.internal.distribute.model.PlanDistributePhoneMaskField;
import com.ts.api.module.match.plan.internal.distribute.model.PlanDistributePhoneMd5Field;
import com.ts.api.module.match.plan.internal.distribute.model.PlanDistributeResult;
import com.ts.api.module.match.plan.internal.selection.base.BasePriceSort;
import com.ts.api.module.product.entity.po.ProductPlanPO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.TimeUnit;

/**
 *  自有渠道-价格优先
 *
 *  @author Pan
 */
@Component
public class ChannelPriceSelection implements PlanSelection {

    @Autowired
    private BasePriceSort basePriceSort;

    @Override
    public PlanDistributeResult select(List<PlanDistributeResult> listSucMatchResult) {
        if (basePriceSort == null) {
            basePriceSort = new BasePriceSort();
        }

        //  合并实体
        List<PlanDistributeResult> mergeResults = CollUtils.newArrayList();

        //  手机号md5-价格排序
        List<PlanDistributeResult> phoneMd5Results = basePriceSort.sortByPhoneMd5(listSucMatchResult);
        mergeResults.addAll(phoneMd5Results);

        //  手机号掩码模式-价格排序
        List<PlanDistributeResult> phoneMaskResults = basePriceSort.sortByPhoneMask(listSucMatchResult);
        mergeResults.addAll(phoneMaskResults);

        // 统一排序逻辑
        mergeResults.sort(
            // 主排序：价格降序（从高到低）
            Comparator.comparing((PlanDistributeResult result) -> {
                    // 从MD5模式获取价格
                    PlanDistributePhoneMd5Field phoneMd5Field = result.getPlanDistributeField().getPhoneMd5Field();
                    if (ValidParam.isNotNull(phoneMd5Field)) {
                        return phoneMd5Field.getPrice();
                    }

                    // 从掩码模式获取价格（取集合中第一个的价格）
                    List<PlanDistributePhoneMaskField> listPhoneMaskField = result.getPlanDistributeField().getListPhoneMaskField();
                    if (ValidParam.isNotEmpty(listPhoneMaskField)) {
                        return listPhoneMaskField.getFirst().getPrice();
                    }
                    // 默认返回0
                    return BigDecimal.ZERO;
                },
                // 降序排序
                Comparator.reverseOrder())
            //  本地机构优先
            .thenComparing((PlanDistributeResult result) -> result.getProductPlanPO().getPriorityLocalOrg(), Comparator.reverseOrder())
        );

        //  同价位平均分配分发
        PlanDistributeResult planDistributeResult = this.samePriceAllocate(mergeResults);
        return planDistributeResult;
    }

    /**
     *  同价位平均分配分发-平均分配
     *
     *  @param  mergeResults   已经合并并且排序好的数据
     *  @return ProductPlanPO
     */
    private PlanDistributeResult samePriceAllocate(List<PlanDistributeResult> mergeResults) {
        //  长度1放弃分配
        if (mergeResults.size() == 1) {
            return mergeResults.getFirst();
        }

        //  分组价格
        Map<BigDecimal, List<PlanDistributeResult>> priceMap = MapUtils.newLinkedHashMap();
        for (PlanDistributeResult planDistributeResult : mergeResults) {
            PlanDistributeField planDistributeField = planDistributeResult.getPlanDistributeField();
            BigDecimal price = null;

            //  获取md5价格值
            PlanDistributePhoneMd5Field phoneMd5Field = planDistributeField.getPhoneMd5Field();
            if (ValidParam.isNotNull(phoneMd5Field)) {
                price = phoneMd5Field.getPrice();
            }

            //  获取掩码模式价格值
            List<PlanDistributePhoneMaskField> listPhoneMaskField = planDistributeField.getListPhoneMaskField();
            if (ValidParam.isNotEmpty(listPhoneMaskField)) {
                PlanDistributePhoneMaskField first = listPhoneMaskField.getFirst();
                price = first.getPrice();
            }

            //  分组添加
            List<PlanDistributeResult> list = priceMap.get(price);
            if (ValidParam.isEmpty(list)) {
                list = CollUtils.newArrayList();
            }
            list.add(planDistributeResult);
            priceMap.put(price, list);
        }

        //  最小被分发的计划
        TreeMap<Integer, ProductPlanPO> minAllocateMap = new TreeMap<>();
        Iterator<Map.Entry<BigDecimal, List<PlanDistributeResult>>> priceMapIterator = IteratorUtils.entrySet(priceMap);
        outer: while (priceMapIterator.hasNext()) {
            Map.Entry<BigDecimal, List<PlanDistributeResult>> next = priceMapIterator.next();
            List<PlanDistributeResult> listMatchResult = next.getValue();
            //  最高单价只返回一条则不搜索
            if (listMatchResult.size() == 1) {
                minAllocateMap.put(1, listMatchResult.getFirst().getProductPlanPO());
                break;
            }

            //  搜索同价格未被分发过的机构计划
            for (PlanDistributeResult planDistributeResult : listMatchResult) {
                ProductPlanPO productPlanPO = planDistributeResult.getProductPlanPO();
                Object increment = MatchProductPlanRedisKey.PRICE_PRODUCT_PLAN.get(ClassConvertUtils.toStr(productPlanPO.getId()));
                //  此机构计划从未参与分发时将直接返回
                if (increment == null) {
                    minAllocateMap.put(1, productPlanPO);
                    break outer;
                }
                Integer incrementInt = ClassConvertUtils.toInt(increment);
                minAllocateMap.put(incrementInt, productPlanPO);
            }
        }

        //  如果最小分发中只有一个同价位，则直接返回首个，不记录平均分发次数
        if (minAllocateMap.size() == 1) {
            return mergeResults.getFirst();
        }

        //  获取首个元素-记录redis操作-->自增计划-->并设置今日都明日0点自动清理
        ProductPlanPO minPlan = minAllocateMap.firstEntry().getValue();
        String key = ClassConvertUtils.toStr(minPlan.getId());

        MatchProductPlanRedisKey.PRICE_PRODUCT_PLAN.increment(key);

        long tomorrowMidnightMillis = DateUtils.getTomorrowMidnightMillis();
        MatchProductPlanRedisKey.PRICE_PRODUCT_PLAN.expire(key, tomorrowMidnightMillis, TimeUnit.MILLISECONDS);

        //  获取分配数据
        return CollUtils.findOne(mergeResults, t -> t.getProductPlanPO().getId().equals(minPlan.getId()));
    }
}
